package cn.jsxz.common.utils.AlipayUtil;

import cn.jsxz.common.utils.DateTimeUtil.DateUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.setting.dialect.Props;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayFundTransOrderQueryModel;
import com.alipay.api.domain.AlipayFundTransToaccountTransferModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundTransOrderQueryRequest;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.request.AlipayOpenPublicQrcodeCreateRequest;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.request.AlipayUserInfoShareRequest;
import com.alipay.api.response.AlipayFundTransOrderQueryResponse;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.alipay.api.response.AlipayOpenPublicQrcodeCreateResponse;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * 支付宝支付通用工具类
 *
 * @author zy
 * @ClassName: AliPayUtil
 * @Description: TODO
 */
public class AliPayUtil {

    private static final Logger LOGGER = Logger.getLogger(AliPayUtil.class);
    static String URL = "https://openapi.alipay.com/gateway.do";// 支付宝网关（固定）
    static String FORMAT = "json";// 参数返回格式，只支持json
    static String APP_ID = "2018040402503347";// props.getStr("APP_ID");//APPID
    // 即创建应用后生成
    static String APP_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDoCdiXCphRF/qfYRDOWwYGblBAKTLBU6FI5YgH2ho2A8FlxNYqir4WWKPjTTToJxGa2UId3sOHGYtNZhNJIBTG2L5ajnuJJMRZki09iVyommtO++QuGR5MH/z5GyCR/CHSiKa79bzTJR9r/CTrumXLo9LX+f8WqYlDRfgDsqDxchUgOepnJy5xHx9E2P9StLYHR5uOpQAeBz8VXw42b5wfjOx3tkHREaO1tv/xCd6BMy50zs/k9vTh6ABwID9i8VlevBltBCzHsR1fyqaAyWgeTxrOQQBk9sUeccf5nDjjSE+yFzpu/6cIctoQ9bq3P5VE+wQtithgQYypk8OofFwNAgMBAAECggEBAKYv9xomknTyMaPYx0qkUqpkc8GgQCPKm+czzbuh78fj5K3YznLlr8MddTOk5lGnOaqoE/yEwZGPMAAdLY7gFUFdlugQyFWvKZnlYdWC/gQbpOOK8SA7CUIIXwyi6y7jX+4DxTc1hynKmriifGcAt0ukZ6wb9yDqB89Q25L6at7BMxD/Q0Y+/ZLouRecl22XCqwdV1g+vDImj/Ub8dIQGCLaRSFJ3J2tTD+eByEtSFCpRjjC9IGdSLJm7x8jVTb07bs8q5KbPtUnM1tZzWmRnqh8nQ1bEiuX7CLuY+U/D4wWCgmIJTJr2Qk5ccsmPETVHd/WR5mOuX+iBtnr2hOgRkECgYEA/XYBG77oIh+NXf8vZh6ZACLqQ2BhatFwGuGHOTF829aXFAOlk64tFOL+kAXm1RhLZFqqzv4HfzcyhKNv7iPBHSIPgvYhwo7ZJQA6uXTdSYxW9JzDZ8JnfnC8hlUK/2WakH+Q4fQBqbfzzDQ6TxUDc2U3dNxSzRiUsp5gRTq3IIUCgYEA6lzndvs416qOJPgvRTjJA/cawQfeDI//a96yG24zN2JlRVm0vLY/4VC9OMLUXC4XeXWCtfjNyPC1JeYMIM2D6vMbvzAb3At/tfORDmVRmGl7l9rbyhlkF79l39Ut1l/hWhqzYXzDsziudzgsfC+urzFo1IH0QYYHKA7fkVMFp+kCgYAx87O8OB+fugAuakB5K8aTlE3/AVuxpZ0mbxQrXWlyGhSkSSO0uzr/Rs1MrR0VGjihioznRoFLvSEjquJAWKOSjkfoU4HLykNZW3Y3XqTN/e6VPt/z7whejvFYuCH2u5t+puVy4pgBTtOphxGGzGllsKkBSvq2mQWVPklS24OD0QKBgGh3gyGxOBRCTVxDWObVOh1PX5idxif5ZBSUTvYVODU+4f94ziy0XGM2FzKe/gQc84/LhrlQr4IbcdPz6IISufPX7A1cB38djQ7xBD7TgPycQGBfSUub59cCFQoiP21ojc4ZSs5wy9cus+4mlwXAR3CGaMEZMGSotrXvc06XIFVJAoGBAM9aDDhvku186l8Sn7RruHh1ZUk21+2Ul5lav4A8J3rRpbXGEQ1Bk7uSv7aIQ9YYJ7mkH292YBDTIBzvKhO3hdGLDOGyPRyrOCBdkpewDSCfnCkxw/zJe6JsWVfNTmeJHmRtHb3B+rDSmSDMuZJco5IE+jKdmJm3OnBGXM5xj1ii";// props.getStr("APP_PRIVATE_KEY");//开发者私钥，由开发者自己生成
    static String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgAgdZ1cLt9yfyWXiyvUvYlGgXjTrSZbuqLmRJVd7Omv3lSNHL/FjE5GciLSVdyMe/J+pqd1sUPlDLNtcdyUKnD3hk+xEzdzXR9pk5yxAz0QxY3+Z7fUob3tN5Up1jNT5NxFDBVaFBoF1905bzCzIX63EFuSgw6BevVRRRKG2uefeVWxrmJFkJQkB3RYVEUoikhlRqEeMuncxz4qtKRWhog12YQnu52swrvcUgHzFM4dYmLIvWIYQgOYwBRocOY0r1WGcVct3gaQf3ObByAvUotweUBDsLmbswBebdTuWQQS95pV8iWyt/dlez+/sn/VDr5nMkVogmgYbsPjzPkIz4QIDAQAB";// props.getStr("ALIPAY_PUBLIC_KEY");//支付宝公钥，由支付宝生成
    static String CHARSET = "utf-8";// gbk
    static String SIGN_TYPE = "RSA2";// 商户生成签名字符串所使用的签名算法类型，目前支持RSA2和RSA，推荐使用RSA2
    // 实例化客户端
    private static AlipayClient alipayClient = new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET,
            ALIPAY_PUBLIC_KEY, SIGN_TYPE);

    /**
     * 创建支付宝连接
     *
     * @return
     */
    private static AlipayClient alipayClient() {
        // 读取配置文件
        Props props = new Props("alipy.properties", "utf-8");
        String URL = props.getStr("URL");// "https://openapi.alipay.com/gateway.do";//支付宝网关（固定）
        String FORMAT = props.getStr("FORMAT");// "json";//参数返回格式，只支持json
        String APP_ID = props.getStr("APP_ID");// APPID 即创建应用后生成
        String APP_PRIVATE_KEY = props.getStr("APP_PRIVATE_KEY");// 开发者私钥，由开发者自己生成
        String ALIPAY_PUBLIC_KEY = props.getStr("ALIPAY_PUBLIC_KEY");// 支付宝公钥，由支付宝生成
        String CHARSET = props.getStr("CHARSET");// "utf-8";//gbk
        String SIGN_TYPE = props.getStr("SIGN_TYPE");// "RSA2";//商户生成签名字符串所使用的签名算法类型，目前支持RSA2和RSA，推荐使用RSA2
        // String shouquanurl = props.getStr("shouquanurl");
        // 实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET,
                ALIPAY_PUBLIC_KEY, SIGN_TYPE);
        return alipayClient;
    }

    /**
     * 获取支付宝授权字符串sign
     *
     * @return 整个授权参数信息的签名 sign，即此行以上参数key和value通过&拼接的字符串的签名值，对此字符串签名后需做URL编码
     */
    public static String getAliPaySign() {
        Props props = new Props("alipy.properties", "utf-8");
        SortedMap<String, String> map = new TreeMap<>();
        // 服务对应的名称，常量值为com.alipay.account.auth
        map.put("apiname", "com.alipay.account.auth");
        // 接口名称，常量值为alipay.open.auth.sdk.code.get
        map.put("method", "alipay.open.auth.sdk.code.get");
        // 支付宝分配给开发者的应用ID
        map.put("app_id", props.getStr("APP_ID"));
        // 调用来源方的标识，常量值为mc
        map.put("app_name", "mc");
        // 调用业务的类型，常量值为openservice
        map.put("biz_type", "openservice");
        // 签约的支付宝账号对应的支付宝唯一用户号，以2088开头的16位纯数字组成
        map.put("pid", props.getStr("PID"));
        // 产品码，常量值为APP_FAST_LOGIN
        map.put("product_id", "APP_FAST_LOGIN");
        // 授权范围，常量值为kuaijie
        map.put("scope", "kuaijie");
        // 商户标识该次用户授权请求的ID，该值在商户端应保持唯一
        map.put("target_id", RandomUtil.randomUUID().replaceAll("-", ""));
        // 标识授权类型，取值范围： AUTHACCOUNT代表授权； LOGIN代表登录
        map.put("auth_type", "AUTHACCOUNT");
        // 商户生成签名字符串所使用的签名算法类型，目前支持RSA2和RSA，推荐使用RSA2
        map.put("sign_type", "RSA2");
        // 整个授权参数信息的签名，即此行以上参数key和value通过&拼接的字符串的签名值，对此字符串签名后需做URL编码
        String sign = AlipaySignature.getSignCheckContentV2(map);
        return sign;

    }
    // 根据auto获取支付宝token

    /**
     * 根据auth_cod取token
     *
     * @param auth_code
     * @return token
     * @throws AlipayApiException
     */
    public static String getAliPayToken(String auth_code) throws AlipayApiException {
        AlipayClient alipayClient = alipayClient();
        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
        // 固定参数，根据auth_code取值
        request.setGrantType("authorization_code");
        request.setCode(auth_code);
        AlipaySystemOauthTokenResponse oauthTokenResponse = alipayClient.execute(request);
        // 获取token
        String accessToken = oauthTokenResponse.getAccessToken();
        return accessToken;
    }

    //

    /**
     * 根据token获取用户基本信息对象
     *
     * @param accessToken
     * @return userinfoShareResponse
     * @throws AlipayApiException
     */
    public static AlipayUserInfoShareResponse getAlipayUserInfoById(String accessToken) throws AlipayApiException {
        AlipayClient alipayClient = alipayClient();
        AlipayUserInfoShareRequest alipayUserInfoShareRequest = new AlipayUserInfoShareRequest();
        AlipayUserInfoShareResponse userinfoShareResponse = alipayClient.execute(alipayUserInfoShareRequest,
                accessToken);
        return userinfoShareResponse;
    }

    /**
     * 企业转账 ,提现
     *
     * @param bizContent 拼接好的json字符串
     * @return
     * @throws AlipayApiException
     */
    public static AlipayFundTransToaccountTransferResponse transferAccounts(String bizContent)
            throws AlipayApiException {
        AlipayClient alipayClient = alipayClient();
        AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();
        request.setBizContent(bizContent);
        AlipayFundTransToaccountTransferResponse response = alipayClient.execute(request);
        return response;
    }

    /**
     * @param params map包含如下参数（参数名称固定，不可变）
     *               out_biz_no,商户转账唯一订单号。发起转账来源方定义的转账单据ID，用于将转账回执通知给来源方。不同来源方给出的ID可以重复，同一个来源方必须保证其ID的唯一性。只支持半角英文、数字，及“-”、“_”。
     *               payee_type,收款方账户类型。可取值：1、ALIPAY_USERID：支付宝账号对应的支付宝唯一用户号。以2088开头的16位纯数字组成。2、ALIPAY_LOGONID：支付宝登录号，支持邮箱和手机号格式。
     *               payee_account,收款方账户。与payee_type配合使用。付款方和收款方不能是同一个账户。
     *               amount,转账金额，单位：元。只支持2位小数，小数点前最大支持13位，金额必须大于等于0.1元。最大转账金额以实际签约的限额为准。
     *               remark,转账备注（支持200个英文/100个汉字）。当付款方为企业账户，且转账金额达到（大于等于）50000元，remark不能为空。收款方可见，会展示在收款用户的收支详情中。
     *               payer_show_name
     *               （可选）付款方姓名（最长支持100个英文/50个汉字）。显示在收款方的账单详情页。如果该字段不传，则默认显示付款方的支付宝认证姓名或单位名称。
     *               payee_real_name
     *               （可选）收款方真实姓名（最长支持100个英文/50个汉字）。如果本参数不为空，则会校验该账户在支付宝登记的实名是否与收款方真实姓名一致。
     * @return 拼接号的bizContent字符串
     */
    public static String getBizContent(Map<String, String> params) {
        String out_biz_no = params.get("out_biz_no");
        String payee_type = params.get("payee_type");
        String payee_account = params.get("payee_account");
        String remark = params.get("remark");
        String amount = params.get("amount");
        String payer_show_name = params.get("payer_show_name");
        String payee_real_name = params.get("payee_real_name");
        StringBuffer sf = new StringBuffer();
        sf.append("{");
        sf.append("\"out_biz_no\":\"" + out_biz_no + "\",");
        sf.append("\"payee_type\":\"" + payee_type + "\",");
        sf.append("\"payee_account\":\"" + payee_account + "\",");
        sf.append("\"amount\":\"" + amount + "\",");
        if (null != payer_show_name && !"".equals(payer_show_name)) {
            sf.append("\"payer_show_name\":\"" + payer_show_name + "\",");
        }
        if (null != payee_real_name && !"".equals(payee_real_name)) {
            sf.append("\"payee_real_name\":\"" + payee_real_name + "\",");
        }
        sf.append("\"remark\":\"" + remark + "\"");
        sf.append("}");
        System.out.println(sf.toString());
        return sf.toString();
    }
    // 退款
    // 解绑

    /**
     * 将异步通知的参数转化为Map
     *
     * @param request
     * @return {Map<String, String>}
     */
    public static Map<String, String> toMap(HttpServletRequest request) {
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 乱码解决，这段代码在出现乱码时使用。
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        return params;
    }

    public static String encryptAndSign(String bizContent, String alipayPublicKey, String cusPrivateKey, String charset,
                                        boolean isEncrypt, boolean isSign, String signType) throws AlipayApiException {
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isEmpty(charset)) {
            charset = AlipayConstants.CHARSET_GBK;
        }
        sb.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>");
        if (isEncrypt) {// 加密
            sb.append("<alipay>");
            String encrypted = AlipaySignature.rsaEncrypt(bizContent, alipayPublicKey, charset);
            sb.append("<response>" + encrypted + "</response>");
            sb.append("<encryption_type>AES</encryption_type>");
            if (isSign) {
                String sign = AlipaySignature.rsaSign(encrypted, cusPrivateKey, charset, signType);
                sb.append("<sign>" + sign + "</sign>");
                sb.append("<sign_type>");
                sb.append(signType);
                sb.append("</sign_type>");
            }
            sb.append("</alipay>");
        } else if (isSign) {// 不加密，但需要签名
            sb.append("<alipay>");
            sb.append("<response>" + bizContent + "</response>");
            String sign = AlipaySignature.rsaSign(bizContent, cusPrivateKey, charset, signType);
            sb.append("<sign>" + sign + "</sign>");
            sb.append("<sign_type>");
            sb.append(signType);
            sb.append("</sign_type>");
            sb.append("</alipay>");
        } else {// 不加密，不加签
            sb.append(bizContent);
        }
        return sb.toString();
    }

    /**
     * 创建二维码
     *
     * @param type
     * @param codeid
     */
    public static AlipayOpenPublicQrcodeCreateResponse createCode(Integer type, String codeid)
            throws AlipayApiException {
        Props props = new Props("alipy.properties", "utf-8");
        String ali_appid = props.getStr("ALI_APPID");
        String ali_pubkey = props.getStr("ALI_PUBKEY");
        String ali_prikey = props.getStr("ALI_PRIKEY");
        String qrcode_goto_url = props.getStr("QRCODE_GOTO_URL");
        qrcode_goto_url += "?type=" + type + "&codeid=" + codeid;

        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", ali_appid,
                ali_prikey, "json", "utf-8", ali_pubkey, "RSA2");
        AlipayOpenPublicQrcodeCreateRequest request = new AlipayOpenPublicQrcodeCreateRequest();
        if (type == 1) {
            request.setBizContent("{" + "\"code_info\":{" + "\"scene\":{" + "\"scene_id\":\"1234\"" + "      },"
                    + "\"goto_url\":\"" + qrcode_goto_url + "\"" + "    }," + "\"code_type\":\"TEMP\","
                    + "\"expire_second\":\"1800\"," + "\"show_logo\":\"Y\"" + "  }");
        } else {
            request.setBizContent("{" + "\"code_info\":{" + "\"scene\":{" + "\"scene_id\":\"1234\"" + "      },"
                    + "\"goto_url\":\"" + qrcode_goto_url + "\"" + "    }," + "\"code_type\":\"PERM\","
                    + "\"show_logo\":\"Y\"" + "  }");
        }

        AlipayOpenPublicQrcodeCreateResponse response = alipayClient.execute(request);
        LOGGER.info("创建二维码的返回值:" + BeanUtil.beanToMap(response));
        return response;
    }

    /**
     * 单笔转账到支付宝账户
     * https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.54Ty29&treeId=193&articleId=106236&docType=1
     *
     * @return
     * @throws AlipayApiException
     */
    public static boolean transfer(AlipayFundTransToaccountTransferModel model) throws AlipayApiException {
        AlipayFundTransToaccountTransferResponse response = transferToResponse(model);
        String result = response.getBody();
        // log.info("transfer result>"+result);
        System.out.println("transfer result>" + result);
        if (response.isSuccess()) {
            return true;
        } else {
            // 调用查询接口查询数据
            JSONObject jsonObject = JSONObject.parseObject(result);
            String out_biz_no = jsonObject.getJSONObject("alipay_fund_trans_toaccount_transfer_response")
                    .getString("out_biz_no");
            AlipayFundTransOrderQueryModel queryModel = new AlipayFundTransOrderQueryModel();
            model.setOutBizNo(out_biz_no);
            boolean isSuccess = transferQuery(queryModel);
            if (isSuccess) {
                return true;
            }
        }
        return false;
    }

    public static AlipayFundTransToaccountTransferResponse transferToResponse(
            AlipayFundTransToaccountTransferModel model) throws AlipayApiException {
        AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();
        request.setBizModel(model);
        return alipayClient.execute(request);
    }

    /**
     * 转账查询接口
     *
     * @return
     * @throws AlipayApiException
     */
    public static boolean transferQuery(AlipayFundTransOrderQueryModel model) throws AlipayApiException {
        AlipayFundTransOrderQueryResponse response = transferQueryToResponse(model);
        // log.info("transferQuery result>"+response.getBody());
        System.out.println("transferQuery result>" + response.getBody());
        if (response.isSuccess()) {
            return true;
        }
        return false;
    }

    public static AlipayFundTransOrderQueryResponse transferQueryToResponse(AlipayFundTransOrderQueryModel model)
            throws AlipayApiException {
        AlipayFundTransOrderQueryRequest request = new AlipayFundTransOrderQueryRequest();
        request.setBizModel(model);
        return alipayClient.execute(request);
    }

    /**
     * 单笔转账到支付宝账户
     * https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.54Ty29&treeId=193&articleId=106236&docType=1
     */
    public void transfer() {
        @SuppressWarnings("unused")
        boolean isSuccess = false;
        String total_amount = "100";
        String orderNumber = DateUtil.dataStrToDate(new Date(), "yyyyMMddHHmmssSSS");
        AlipayFundTransToaccountTransferModel model = new AlipayFundTransToaccountTransferModel();
        model.setOutBizNo(orderNumber);// 生成订单号
        model.setPayeeType("ALIPAY_LOGONID");// 固定值
        model.setPayeeAccount("624841536@qq.com");// 转账收款账户
        model.setAmount(total_amount);// 金额
        model.setPayerShowName("测试退款");
        model.setPayerRealName("沙箱环境");// 账户真实名称
        model.setRemark("javen测试单笔转账到支付宝");

        try {
            isSuccess = transfer(model);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // renderJson(isSuccess);
    }

    public static void main(String[] args) {
        // aliPaySDKTest();
    }
}
